home *** CD-ROM | disk | FTP | other *** search
/ Aminet 3 / Aminet 3 - July 1994.iso / Aminet / disk / misc / Mtools207.lha / Mtools-2.0.7 / src / init.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-28  |  9.3 KB  |  423 lines

  1. /*
  2.  * Initialize an MSDOS diskette.  Read the boot sector, and switch to the
  3.  * proper floppy disk device to match the format on the disk.  Sets a bunch
  4.  * of global variables.  Returns 0 on success, or 1 on failure.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include "msdos.h"
  12. #include "amiga_devices.h"
  13.  
  14. struct device_data * ddata = 0;
  15.  
  16. #ifdef AMIGA
  17. #define DEFAULT_CACHE_SIZE 128
  18. #else
  19. #define FULL_CYL
  20. #define DEFAULT_CACHE_SIZE 1
  21. #endif
  22.  
  23. #define WORD(x) ((boot->x)[0] + ((boot->x)[1] << 8))
  24. #define DWORD(x) ((boot->x)[0] + ((boot->x)[1] << 8) + ((boot->x)[2] << 16) + ((boot->x)[3] << 24))
  25.  
  26. unsigned int num_clus;            /* total number of cluster */
  27. int num_fat;                /* the number of FAT tables */
  28. long disk_offset;            /* skip this many bytes */
  29. int fat_bits;                /* the FAT encoding scheme */
  30.  
  31. extern int fd, fat_len, dir_len, dir_start, clus_size, dir_dirty, disk_dirty;
  32. extern int fat_error, disk_size;
  33. extern long disk_current;
  34. extern char *mcwd;
  35. extern unsigned char *fat_buf, *disk_buf, *dir_buf;
  36. extern struct device devices[];
  37. static struct bootsector *read_boot();
  38.  
  39. void free_amiga_device(void) {
  40.     
  41.     if (ddata != 0) {
  42.         free_device (ddata);
  43.         ddata = 0;
  44.     }
  45. }
  46.  
  47. int
  48. init(drive, mode)
  49. char drive;
  50. int mode;
  51. {
  52.     int fat_start, tracks, heads, sectors, old_dos;
  53.     char buf[256], *malloc(), *name, *expand();
  54.     void perror(), exit(), reset_chain(), free(), fat_read();
  55.     struct bootsector *boot;
  56.     struct device *dev;
  57.  
  58.     if (fd != -1) {
  59.         close(fd);
  60.         free((char *) fat_buf);
  61.         free((char *) disk_buf);
  62.         free((char *) dir_buf);
  63.     }
  64.     
  65.     free_amiga_device();
  66.     
  67.                     /* check out the drive letter */
  68.     dev = devices;
  69.     while (dev->drive) {
  70.         if (dev->drive == drive)
  71.             break;
  72.         dev++;
  73.     }
  74.     if (!dev->drive) {
  75.         fprintf(stderr, "Drive '%c:' not supported\n", drive);
  76.         return(1);
  77.     }
  78.                     /* open the device */
  79.     while (dev->name) {
  80.         if (dev->drive != drive)
  81.             break;
  82.  
  83.         if (dev->heads >= 0) {
  84.             name = expand(dev->name);
  85.             if ((fd = open(name, mode | dev->mode)) < 0) {
  86.                 sprintf(buf, "init: open \"%s\"", name);
  87.                 perror(buf);
  88.                 exit(1);
  89.             }
  90.                     /* lock the device on writes */
  91.             if (mode == 2 && lock_dev(fd)) {
  92.                 fprintf(stderr, "Device \"%s\" is busy\n", dev->name);
  93.                 exit(1);
  94.             }
  95.                         /* set default parameters, if needed */
  96.             if (dev->gioctl) {
  97.                 if ((*(dev->gioctl)) (fd, dev->tracks, dev->heads, dev->sectors))
  98.                     goto try_again;
  99.             }
  100.         } else {
  101.             /* open amiga device!! */
  102.             
  103.             ddata = alloc_device  (dev->name, dev->mode, 0, sizeof(struct IOStdReq));
  104.             
  105.             if (ddata == NULL) {
  106.                 fprintf(stderr, "unable to open \"%s\" \n", dev->name);
  107.                 exit(1);
  108.             }
  109.             
  110.             fd = 1;
  111.             
  112.             atexit( free_amiga_device );
  113.         }
  114.         
  115.                     /* read the boot sector */
  116.         disk_offset = dev->offset;
  117.         if ((boot = read_boot()) == NULL)
  118.             goto try_again;
  119.  
  120.         heads = WORD(nheads);
  121.         sectors = WORD(nsect);
  122.         if (heads && sectors)
  123.             tracks = WORD(psect) / (unsigned) (heads * sectors);
  124.  
  125.                     /* sanity checking */
  126.         old_dos = 0;
  127.         if (!heads || heads > 100 || !sectors || sectors > 500 || tracks > 5000 || !boot->clsiz) {
  128.             /*
  129.              * The above technique will fail on diskettes that
  130.              * have been formatted with very old MSDOS, so we
  131.              * resort to the old table-driven method using the
  132.              * media signature (first byte in FAT).
  133.              */
  134.             unsigned char temp[MSECTOR_SIZE];
  135.             
  136.             if (ddata != 0) {
  137.                 if (MSECTOR_SIZE != (int) device_read( ddata, (ulong) disk_offset+MSECTOR_SIZE, (ulong) MSECTOR_SIZE, temp) ) {
  138.                     temp[0] = '0';
  139.                 }
  140.             }
  141.             else {
  142.                 if (read(fd, (char *) temp, MSECTOR_SIZE) != MSECTOR_SIZE) {
  143.                     temp[0] = '0';
  144.                 }
  145.             }
  146.  
  147.             switch (temp[0]) {
  148.                 case 0xfe:    /* 160k */
  149.                     tracks = 40;
  150.                     sectors = 8;
  151.                     heads = 1;
  152.                     dir_start = 3;
  153.                     dir_len = 4;
  154.                     clus_size = 1;
  155.                     fat_len = 1;
  156.                     num_clus = 313;
  157.                     break;
  158.                 case 0xfc:    /* 180k */
  159.                     tracks = 40;
  160.                     sectors = 9;
  161.                     heads = 1;
  162.                     dir_start = 5;
  163.                     dir_len = 4;
  164.                     clus_size = 1;
  165.                     fat_len = 2;
  166.                     num_clus = 351;
  167.                     break;
  168.                 case 0xff:    /* 320k */
  169.                     tracks = 40;
  170.                     sectors = 8;
  171.                     heads = 2;
  172.                     dir_start = 3;
  173.                     dir_len = 7;
  174.                     clus_size = 2;
  175.                     fat_len = 1;
  176.                     num_clus = 315;
  177.                     break;
  178.                 case 0xfd:    /* 360k */
  179.                     tracks = 40;
  180.                     sectors = 9;
  181.                     heads = 2;
  182.                     dir_start = 5;
  183.                     dir_len = 7;
  184.                     clus_size = 2;
  185.                     fat_len = 2;
  186.                     num_clus = 354;
  187.                     break;
  188.                 default:
  189.                     fprintf(stderr, "Probable non-MSDOS disk\n");
  190.                     close(fd);
  191.                     fd = -1;
  192.                     return(1);
  193.             }
  194.             fat_start = 1;
  195.             num_fat = 2;
  196.             old_dos = 1;
  197.         }
  198.                     /* check the parameters */
  199.         if (dev->tracks && !dev->gioctl) {
  200.             if (dev->tracks == tracks && dev->heads == heads && dev->sectors == sectors)
  201.                 break;
  202.         }
  203.         else
  204.             break;
  205.  
  206. try_again:    
  207.         free_amiga_device();
  208.         close(fd);
  209.         fd = -1;
  210.         dev++;
  211.     }
  212.     if (fd == -1) {
  213.         if (boot != NULL && dev->tracks)
  214.             fprintf(stderr, "No support for %d tracks, %d heads, %d sector diskettes\n", tracks, heads, sectors);
  215.         return(1);
  216.     }
  217.                     /* set new parameters, if needed */
  218.     if (dev->gioctl) {
  219.         if ((*(dev->gioctl)) (fd, tracks, heads, sectors)) {
  220.             fprintf(stderr, "Can't set disk parameters\n");
  221.             close(fd);
  222.             fd = -1;
  223.             return(1);
  224.         }
  225.     }
  226.  
  227.     /*
  228.      * all numbers are in sectors, except num_clus (which is in clusters)
  229.      */
  230.     if (!old_dos) {
  231.         clus_size = boot->clsiz;
  232.         fat_start = WORD(nrsvsect);
  233.         fat_len = WORD(fatlen);
  234.         dir_start = fat_start + (boot->nfat * fat_len);
  235.         dir_len = WORD(dirents) * MDIR_SIZE / (unsigned) MSECTOR_SIZE;
  236.         /*
  237.          * For DOS partitions > 32M
  238.          */
  239.         if (WORD(psect) == 0)
  240.             num_clus = (unsigned int) (DWORD(bigsect) - dir_start - dir_len) / clus_size;
  241.         else
  242.             num_clus = (unsigned int) (WORD(psect) - dir_start - dir_len) / clus_size;
  243.         num_fat = boot->nfat;
  244.     }
  245.                     /* more sanity checking */
  246.     if (clus_size * MSECTOR_SIZE > MAX_CLUSTER) {
  247.         fprintf(stderr, "Cluster size of %d is larger than max of %d\n", clus_size * MSECTOR_SIZE, MAX_CLUSTER);
  248.         close(fd);
  249.         fd = -1;
  250.         return(1);
  251.     }
  252.     if (!old_dos && WORD(secsiz) != MSECTOR_SIZE) {
  253.         fprintf(stderr, "Sector size of %d is not supported\n", WORD(secsiz));
  254.         close(fd);
  255.         fd = -1;
  256.         return(1);
  257.     }
  258.                     /* full cylinder buffering */
  259.  
  260. #ifdef FULL_CYL
  261.     disk_size = (dev->sectors) ? (sectors * heads) : DEFAULT_CACHE_SIZE;
  262. #else /* FULL_CYL */
  263.     disk_size = (dev->sectors) ? sectors : DEFAULT_CACHE_SIZE;
  264. #endif /* FULL_CYL */
  265.  
  266. /* printf ("disk size: %d\n",disk_size); */
  267.  
  268.     disk_buf = (unsigned char *) malloc((unsigned int) disk_size * MSECTOR_SIZE);
  269.     if (disk_buf == NULL) {
  270.         perror("init: malloc");
  271.         exit(1);
  272.     }
  273.                     /* read the FAT sectors */
  274.     disk_current = -1000L;
  275.     disk_dirty = 0;
  276.     fat_error = 0;
  277.     fat_bits = dev->fat_bits;
  278.     fat_read(fat_start);
  279.                     /* set dir_chain[] to root directory */
  280.     dir_dirty = 0;
  281.     reset_chain(NEW);
  282.     return(0);
  283. }
  284.  
  285. /*
  286.  * Fix the info in the MCWD file to be a proper directory name.  Always
  287.  * has a leading separator.  Never has a trailing separator (unless it is
  288.  * the path itself).
  289.  */
  290.  
  291. char *
  292. fix_mcwd()
  293. {
  294.     FILE *fp;
  295.     struct stat sbuf;
  296.     char *s, *strcpy(), *strcat(), *mcwd_path, *getenv(), *strncpy();
  297.     char buf[BUFSIZ], *file, *expand();
  298.     static char ans[MAX_PATH];
  299.     long now, time();
  300.  
  301.     mcwd_path = getenv("MCWD");
  302.     if (mcwd_path == NULL || *mcwd_path == '\0')
  303.         mcwd_path = "$HOME/.mcwd";
  304.  
  305.     file = expand(mcwd_path);
  306.     if (stat(file, &sbuf) < 0)
  307.         return("A:/");
  308.     /*
  309.      * Ignore the info, if the file is more than 6 hours old
  310.      */
  311.     time(&now);
  312.     if (now - sbuf.st_mtime > 6 * 60 * 60) {
  313.         fprintf(stderr, "Warning: \"%s\" is out of date, contents ignored\n", file);
  314.         return("A:/");
  315.     }
  316.     
  317.     if (!(fp = fopen(file, "r")))
  318.         return("A:/");
  319.  
  320.     if (!fgets(buf, BUFSIZ, fp))
  321.         return("A:/");
  322.  
  323.     buf[strlen(buf) -1] = '\0';
  324.     fclose(fp);
  325.                     /* drive letter present? */
  326.     s = buf;
  327.     if (buf[0] && buf[1] == ':') {
  328.         strncpy(ans, buf, 2);
  329.         ans[2] = '\0';
  330.         s = &buf[2];
  331.     }
  332.     else 
  333.         strcpy(ans, "A:");
  334.                     /* add a leading separator */
  335.     if (*s != '/' && *s != '\\') {
  336.         strcat(ans, "/");
  337.         strcat(ans, s);
  338.     }
  339.     else
  340.         strcat(ans, s);
  341.                     /* translate to upper case */
  342.     for (s = ans; *s; ++s) {
  343.         if (islower(*s))
  344.             *s = toupper(*s);
  345.         if (*s == '\\')
  346.             *s = '/';
  347.     }
  348.                     /* if only drive, colon, & separator */
  349.     if (strlen(ans) == 3)
  350.         return(ans);
  351.                     /* zap the trailing separator */
  352.     if (*--s == '/')
  353.         *s = '\0';
  354.     return(ans);
  355. }
  356.  
  357. /*
  358.  * Read the boot sector.  We glean the disk parameters from this sector.
  359.  */
  360.  
  361. static struct bootsector *
  362. read_boot()
  363. {
  364.     long lseek();
  365.     static struct bootsector boot;
  366.     
  367.     if (ddata != 0) {
  368.         if (MSECTOR_SIZE != (int) device_read( ddata, (ulong) disk_offset, (ulong) MSECTOR_SIZE, &boot) ) {
  369.             return(NULL);
  370.         }
  371.     }
  372.     else {
  373.         if (lseek(fd, disk_offset, 0) < 0) {
  374.             return(NULL);
  375.         }
  376.         /* read the first sector */
  377.         if (read(fd, (char *) &boot, MSECTOR_SIZE) != MSECTOR_SIZE) {
  378.             return(NULL);
  379.         }
  380.     }
  381.  
  382.     return(&boot);
  383. }
  384.  
  385. /*
  386.  * Create an advisory lock on the device to prevent concurrent writes.
  387.  * Uses either lockf, flock, or fcntl locking methods.  See the Makefile
  388.  * and the Configure files for how to specify the proper method.
  389.  */
  390.  
  391. static int
  392. lock_dev(fd)
  393. int fd;
  394. {
  395. #ifdef LOCKF
  396. #include <unistd.h>
  397.  
  398.     if (lockf(fd, F_TLOCK, 0) < 0)
  399.         return(1);
  400. #endif /* LOCKF */
  401.  
  402. #ifdef FLOCK
  403. #include <sys/file.h>
  404.  
  405.     if (flock(fd, LOCK_EX|LOCK_NB) < 0)
  406.         return(1);
  407. #endif /* FLOCK */
  408.  
  409. #ifdef FCNTL
  410. #include <fcntl.h>
  411.     struct flock flk;
  412.  
  413.     flk.l_type = F_WRLCK;
  414.     flk.l_whence = 0;
  415.     flk.l_start = 0L;
  416.     flk.l_len = 0L;
  417.  
  418.     if (fcntl(fd, F_SETLK, &flk) < 0)
  419.         return(1);
  420. #endif /* FCNTL */
  421.     return(0);
  422. }
  423.